package service

import (
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
	"gorm.io/gorm"
	"prod/api/prod"
	"prod/internal/constant"
	"prod/internal/model"
	"prod/pkg/ecode"
	"prod/pkg/util"
	"strconv"
	"strings"
	"time"
)

func (s *Service) checkMenuPermission(ctx context.Context, token *prod.WebToken, pStoreId uint32) (err error) {
	if pStoreId != 0 {
		err = ecode.AppendMessage(constant.ErrPermissionError, "只有总部模式可以查看供货组信息")
		return
	}
	if err = s.dao.CheckPermission(ctx, token, 0); err != nil {
		return
	}
	return
}

// 查看供货组列表（含关联门店）
func (s *Service) GetMenuList(ctx context.Context, req *prod.CommonRequest) (resp *prod.GetMenuListResponse, err error) {
	if err = s.checkMenuPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	var (
		menus       []*model.MenuQueryModel
		allStoreIds []uint32
		storeMap    map[uint32]*prod.StoreSimpleView
	)
	if menus, err = s.dao.GetMenus(ctx, req.Token.SgId); err != nil {
		return
	}
	resp = &prod.GetMenuListResponse{Menus: make([]*prod.MenuView, 0)}
	menuStoreMap := make(map[uint32][]uint32)
	for _, menu := range menus {
		var rawStoreIds []string
		menuStoreMap[menu.ID] = make([]uint32, 0)
		if menu.StoreIds != "" {
			rawStoreIds = strings.Split(menu.StoreIds, ",")
			for _, storeIdStr := range rawStoreIds {
				storeId, _ := strconv.Atoi(storeIdStr)
				menuStoreMap[menu.ID] = append(menuStoreMap[menu.ID], uint32(storeId))
				allStoreIds = append(allStoreIds, uint32(storeId))
			}
		}
	}
	if storeMap, err = s.dao.GetStoreMapByStoreIds(ctx, allStoreIds); err != nil {
		return
	}
	for _, menu := range menus {
		var stores []*prod.StoreSimpleView
		for _, storeId := range menuStoreMap[menu.ID] {
			if _, ok := storeMap[storeId]; ok {
				stores = append(stores, storeMap[storeId])
			}
		}
		resp.Menus = append(resp.Menus, &prod.MenuView{
			Id:             menu.ID,
			Name:           menu.Name,
			Pic:            menu.Pic,
			CanModifyPrice: menu.CanModifyPrice,
			Stores:         stores,
			ProdCount:      menu.ProdCount,
		})
	}
	return
}

// 查看供货组基本属性
func (s *Service) GetMenuInfo(ctx context.Context, req *prod.CommonObjectRequest) (resp *prod.MenuView, err error) {
	if err = s.checkMenuPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	var (
		menuInfo    *model.MenuQueryModel
		rawStoreIds []string
		storeIds    []uint32
		stores      []*prod.StoreSimpleView
	)
	if menuInfo, err = s.dao.GetMenuInfo(ctx, req.Id, req.Token.SgId); err != nil {
		return
	}
	if menuInfo.StoreIds != "" {
		rawStoreIds = strings.Split(menuInfo.StoreIds, ",")
		for _, storeIdStr := range rawStoreIds {
			storeId, _ := strconv.Atoi(storeIdStr)
			storeIds = append(storeIds, uint32(storeId))
		}
	}
	if stores, err = s.dao.GetStoreListByStoreIds(ctx, storeIds); err != nil {
		return
	}
	resp = &prod.MenuView{
		Id:             menuInfo.ID,
		Name:           menuInfo.Name,
		Pic:            menuInfo.Pic,
		CanModifyPrice: menuInfo.CanModifyPrice,
		Stores:         stores,
		ProdCount:      menuInfo.ProdCount,
	}
	return
}

// 新建供货组
func (s *Service) CreateMenu(ctx context.Context, req *prod.CreateMenuRequest) (resp *prod.DefaultResp, err error) {
	if err = s.checkMenuPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		// 锁定正确状态的记录
		if _, err = s.dao.GetMenuByName(
			ctx, req.Name, req.Token.SgId); err == nil {
			err = constant.ErrDuplicateInput
			return
		} else if errors.Cause(err) != gorm.ErrRecordNotFound {
			return
		} else {
			menu := &model.Menu{
				Name:           req.Name,
				SgId:           req.Token.SgId,
				Pic:            req.Pic,
				CanModifyPrice: req.CanModifyPrice,
				Operator:       req.Token.EmpId,
				Status:         sql.NullBool{Valid: true, Bool: true},
			}
			if err = s.dao.Create(ctx, menu); err != nil {
				return
			}
		}
		return
	}); err != nil {
		return
	}
	resp = &prod.DefaultResp{Status: true}
	return
}

// 修改供货组名称 + 是否允许改价
func (s *Service) EditMenu(ctx context.Context, req *prod.EditMenuRequest) (resp *prod.DefaultResp, err error) {
	if err = s.checkMenuPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		// 锁定正确状态的记录
		menu := &model.Menu{}
		if err = s.dao.LockObjectByIDWithoutPStoreId(ctx, menu, req.Id, req.Token.SgId); err != nil {
			return
		}
		if menu.Name != req.Name {
			if _, err = s.dao.GetMenuByName(ctx, req.Name, req.Token.SgId); err != nil {
				if errors.Cause(err) != gorm.ErrRecordNotFound {
					return
				}
			} else {
				err = ecode.AppendMessage(constant.ErrDuplicateInput, "存在同名供货组")
				return
			}
		}
		menu.Name = req.Name
		menu.Pic = req.Pic
		// 是否从允许改价 => 不允许改价
		priceRuleChanged := menu.CanModifyPrice != req.CanModifyPrice && menu.CanModifyPrice == true
		menu.CanModifyPrice = req.CanModifyPrice
		menu.Operator = req.Token.EmpId
		if err = s.dao.Save(ctx, menu); err != nil {
			return
		}
		if priceRuleChanged {
			var menuStores []*model.MenuStore
			if menuStores, err = s.dao.GetMenuStores(ctx, req.Id); err != nil {
				return
			}
			if len(menuStores) != 0 {
				// 发送商品更新消息
				var (
					nsqMsg           []byte
					menuStoreMessage []*prod.MenuUpdateMessage_StoreMessage
				)
				for _, menuStore := range menuStores {
					menuStoreMessage = append(menuStoreMessage, &prod.MenuUpdateMessage_StoreMessage{
						StoreId:   menuStore.StoreId,
						DelIds:    make([]uint64, 0),
						UpdateIds: make([]uint64, 0),
					})
				}
				if nsqMsg, err = json.Marshal(&prod.MenuUpdateMessage{
					Stores:                          menuStoreMessage,
					SgId:                            req.Token.SgId,
					IsAllowModifyChangedToForbidden: priceRuleChanged,
					Timestamp:                       time.Now().Local().Unix(),
				}); err != nil {
					err = ecode.WithStack(err)
					return
				}
				if err = s.dao.PublishUniqueNSQMessage(
					ctx, constant.TopicMenuUpdate, nsqMsg); err != nil {
					return err
				}
			}
		}
		return
	}); err != nil {
		return
	}
	resp = &prod.DefaultResp{Status: true}
	return
}

// 删除供货组（基于供货组ID）
func (s *Service) DeleteMenu(ctx context.Context, req *prod.CommonObjectRequest) (resp *prod.DefaultResp, err error) {
	if err = s.checkMenuPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var menuStores []*model.MenuStore
		menu := &model.Menu{}
		if err = s.dao.LockObjectByIDWithoutPStoreId(ctx, menu, req.Id, req.Token.SgId); err != nil {
			return
		}
		if menuStores, err = s.dao.GetMenuStores(ctx, req.Id); err != nil {
			return
		}
		if len(menuStores) != 0 {
			err = ecode.AppendMessage(constant.ErrForbiddenAction, "供货组存在应用店铺，请先解绑在删除")
		}
		menu.Status = sql.NullBool{}
		menu.Operator = req.Token.EmpId
		if err = s.dao.Save(ctx, menu); err != nil {
			return
		}
		return
	}); err != nil {
		return
	}
	resp = &prod.DefaultResp{Status: true}
	return
}

// 复制供货组（基于供货组ID）
func (s *Service) CopyMenu(ctx context.Context, req *prod.CommonObjectRequest) (resp *prod.DefaultResp, err error) {
	if err = s.checkMenuPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		menu := &model.Menu{}
		if err = s.dao.LockObjectByIDWithoutPStoreId(ctx, menu, req.Id, req.Token.SgId); err != nil {
			return
		}
		menu.ID = 0
		menu.Name = fmt.Sprintf("%s(副本)", menu.Name)
		menu.Operator = req.Token.EmpId
		if len(menu.Name) > 50 {
			err = ecode.BadRequest("供货组名称过长，无法创建副本")
			return
		}
		if _, err = s.dao.GetMenuByName(ctx, menu.Name, req.Token.SgId); err != nil {
			if errors.Cause(err) != gorm.ErrRecordNotFound {
				return
			}
		} else {
			err = ecode.AppendMessage(constant.ErrDuplicateInput, "副本存在同名供货组，请修改名称再复制")
			return
		}
		if err = s.dao.Create(ctx, menu); err != nil {
			return
		}
		var menuProds []*model.MenuProd
		if menuProds, err = s.dao.GetMenuProds(ctx, req.Id); err != nil {
			return
		}
		if len(menuProds) != 0 {
			// 需要复制供货组商品
			for _, menuProd := range menuProds {
				menuProd.MenuId = menu.ID
				menuProd.Operator = req.Token.EmpId
				if err = s.dao.Create(ctx, menuProd); err != nil {
					return
				}
			}
		}
		return
	}); err != nil {
		return
	}
	resp = &prod.DefaultResp{Status: true}
	return
}

// 设置供货组关联门店
func (s *Service) SetMenuStores(ctx context.Context, req *prod.SetMenuStoresRequest) (resp *prod.DefaultResp, err error) {
	if err = s.checkMenuPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	var stores []*prod.StoreSimpleView
	if stores, err = s.dao.GetStoreListByStoreIds(ctx, req.StoreIds); err != nil {
		return
	}
	if len(stores) != len(req.StoreIds) {
		err = ecode.BadRequest("所选门店包含已删除门店，请刷新列表再试")
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var (
			menuStores []*model.MenuStore
			nsqMsg     []byte
			menuProds  []*model.MenuProd
			storeMsgs  []*prod.MenuUpdateMessage_StoreMessage
		)
		menu := &model.Menu{}
		if err = s.dao.LockObjectByIDWithoutPStoreId(ctx, menu, req.Id, req.Token.SgId); err != nil {
			return
		}
		if menuStores, err = s.dao.GetMenuStores(ctx, req.Id); err != nil {
			return
		}
		existStoreMap := make(util.Int32BoolMap)
		var addStoreIds, delStoreIds []uint32
		for _, menuStore := range menuStores {
			existStoreMap[menuStore.StoreId] = true
		}
		for _, storeId := range req.StoreIds {
			if _, ok := existStoreMap[storeId]; ok {
				delete(existStoreMap, storeId)
			} else {
				addStoreIds = append(addStoreIds, storeId)
			}
		}
		delStoreIds = existStoreMap.GetKeys()
		if len(addStoreIds) == 0 && len(delStoreIds) == 0 {
			return
		}
		menuProdIdMap := make(util.Int64BoolMap)
		if menuProds, err = s.dao.GetMenuProds(ctx, req.Id); err != nil {
			return
		}
		for _, menuProd := range menuProds {
			menuProdIdMap[menuProd.ProdId] = true
		}
		if len(addStoreIds) != 0 {
			var affectAddedStores []*model.MenuStore
			if affectAddedStores, err = s.dao.GetMenuStoresByStoreIds(ctx, addStoreIds); err != nil {
				return
			}
			for _, affectStore := range affectAddedStores {
				var affectMenuProds []*model.MenuProd
				updateStoreProdIds := make([]uint64, 0)
				delStoreProdIds := make([]uint64, 0)
				if affectMenuProds, err = s.dao.GetMenuProds(ctx, affectStore.MenuId); err != nil {
					return
				}
				for _, affectMenuProd := range affectMenuProds {
					if _, ok := menuProdIdMap[affectMenuProd.ProdId]; !ok {
						// 因供货组变更需要移除店铺货架的商品列表
						delStoreProdIds = append(delStoreProdIds, affectMenuProd.ProdId)
					} else {
						// 重复的商品需要触发更新信息
						updateStoreProdIds = append(updateStoreProdIds, affectMenuProd.ProdId)
					}
				}
				if len(delStoreProdIds) != 0 || len(updateStoreProdIds) != 0 {
					storeMsgs = append(storeMsgs, &prod.MenuUpdateMessage_StoreMessage{
						StoreId:   affectStore.StoreId,
						DelIds:    delStoreProdIds,
						UpdateIds: updateStoreProdIds,
					})
				}
			}
		}
		if len(delStoreIds) > 0 {
			var affectDeletedStores []*model.MenuStore
			if affectDeletedStores, err = s.dao.GetMenuStoresByStoreIds(ctx, delStoreIds); err != nil {
				return
			}
			delStoreProdIds := menuProdIdMap.GetKeys()
			for _, affectStore := range affectDeletedStores {
				// 移除供货组店铺，商品全部移除货架
				storeMsgs = append(storeMsgs, &prod.MenuUpdateMessage_StoreMessage{
					StoreId:   affectStore.StoreId,
					DelIds:    delStoreProdIds,
					UpdateIds: make([]uint64, 0),
				})
			}
		}
		for _, storeId := range addStoreIds {
			menuStore := &model.MenuStore{
				StoreId:  storeId,
				MenuId:   menu.ID,
				SgId:     req.Token.SgId,
				Operator: req.Token.EmpId,
				Status:   true,
			}
			if err = s.dao.InsertOrUpdate(ctx, menuStore); err != nil {
				return
			}
		}
		for _, storeId := range delStoreIds {
			menuStore := &model.MenuStore{
				StoreId:  storeId,
				MenuId:   menu.ID,
				SgId:     req.Token.SgId,
				Operator: req.Token.EmpId,
				Status:   false,
			}
			if err = s.dao.Save(ctx, menuStore); err != nil {
				return
			}
		}
		if len(storeMsgs) != 0 {
			if nsqMsg, err = json.Marshal(&prod.MenuUpdateMessage{
				Stores:    storeMsgs,
				SgId:      req.Token.SgId,
				Timestamp: time.Now().Local().Unix(),
			}); err != nil {
				err = ecode.WithStack(err)
				return
			}
			if err = s.dao.PublishUniqueNSQMessage(
				ctx, constant.TopicMenuUpdate, nsqMsg); err != nil {
				return err
			}
		}
		return
	}); err != nil {
		return
	}
	resp = &prod.DefaultResp{Status: true}
	return
}

// 查看供货组商品列表
func (s *Service) GetMenuProdList(ctx context.Context, req *prod.GetMenuProdListRequest) (
	resp *prod.GetProdListResponse, err error) {
	resp = &prod.GetProdListResponse{Prods: make([]*prod.SimpleProdView, 0)}
	if err = s.checkMenuPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	var (
		prods       []*model.Product
		menuSkus    []*model.MenuSkuQueryModel
		prodIds     []uint64
		prodTypeMap map[uint32]string
	)
	if prods, resp.Total, err = s.dao.GetMenuProdsByCondition(
		ctx, req.MenuId, req.ProdTypeId, req.Token.SgId, req.PStoreId, req.PageNo, req.PageSize,
		req.Query, req.ExcludedProdIds); err != nil {
		return
	}
	prodMap := make(map[uint64]*model.Product)
	prodTypeIdMap := make(util.Int32BoolMap)
	for _, p := range prods {
		prodIds = append(prodIds, p.ID)
		prodMap[p.ID] = p
		prodTypeIdMap[p.TypeId] = true
	}
	if prodTypeMap, err = s.getProdTypeMapByIds(ctx, prodTypeIdMap.GetKeys(), req.Token.SgId, req.PStoreId); err != nil {
		return
	}
	if menuSkus, err = s.dao.GetMenuSkuInfoByProdIds(ctx, req.MenuId, prodIds); err != nil {
		return
	}
	menuSkuMap := make(map[uint64][]*prod.SimpleSkuView)
	priceRangeDict := make(map[uint64][]uint32)
	for _, sku := range menuSkus {
		if _, ok := menuSkuMap[sku.ProdId]; !ok {
			menuSkuMap[sku.ProdId] = make([]*prod.SimpleSkuView, 0)
		}
		var price uint32
		if sku.MenuPrice.Valid {
			price = uint32(sku.MenuPrice.Int64)
		} else {
			price = sku.SkuPrice
		}
		if skuPrice, ok := priceRangeDict[sku.ProdId]; !ok {
			priceRangeDict[sku.ProdId] = []uint32{price, price}
		} else if skuPrice[1] > price {
			priceRangeDict[sku.ProdId][1] = price
		} else if skuPrice[0] < price {
			priceRangeDict[sku.ProdId][0] = price
		}
		menuSkuMap[sku.ProdId] = append(menuSkuMap[sku.ProdId], &prod.SimpleSkuView{
			Id:    sku.SkuId,
			Name:  strings.Join(sku.Items, "/"),
			Price: price,
		})
	}

	for _, prodInfo := range prods {
		var pic string
		if len(prodInfo.TitlePics) > 0 {
			pic = prodInfo.TitlePics[0]
		}
		resp.Prods = append(resp.Prods, &prod.SimpleProdView{
			Id:           prodInfo.ID,
			Name:         prodInfo.Name,
			ProdTypeId:   prodInfo.TypeId,
			ProdTypeName: prodTypeMap[prodInfo.TypeId],
			PriceRange:   priceRangeDict[prodInfo.ID],
			TitlePic:     pic,
			Skus:         menuSkuMap[prodInfo.ID],
		})
	}
	return
}

// 批量导入商品到供货组
func (s *Service) BatchAddProdsToMenu(ctx context.Context, req *prod.BatchMenuProdsRequest) (resp *prod.DefaultResp, err error) {
	if err = s.checkMenuPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		menu := &model.Menu{}
		if err = s.dao.LockObjectByIDWithoutPStoreId(ctx, menu, req.MenuId, req.Token.SgId); err != nil {
			return
		}
		var prods []*model.Product
		if prods, err = s.dao.GetProdByIDs(ctx, req.ProdIds, req.Token.SgId, req.PStoreId); err != nil {
			return
		}
		if len(prods) != len(req.ProdIds) {
			err = ecode.AppendMessage(constant.ErrNeedRefresh, "所选商品包含已删除商品，请刷新列表重试")
		}
		if err = s.dao.CheckMenuProdsExists(ctx, req.MenuId, req.ProdIds); err != nil {
			if errors.Cause(err) != gorm.ErrRecordNotFound {
				return
			}
		} else {
			err = ecode.AppendMessage(constant.ErrNeedRefresh, "包含已在供货组商品")
		}
		for _, prodId := range req.ProdIds {
			menuSku := &model.MenuProd{
				MenuId:   req.MenuId,
				ProdId:   prodId,
				SgId:     req.Token.SgId,
				Operator: req.Token.EmpId,
				Status:   true,
			}
			if err = s.dao.InsertOrUpdate(ctx, menuSku); err != nil {
				return
			}
		}
		return
	}); err != nil {
		return
	}
	resp = &prod.DefaultResp{Status: true}
	return
}

// 修改供货组商品价格
func (s *Service) EditMenuProd(ctx context.Context, req *prod.EditMenuProdRequest) (resp *prod.DefaultResp, err error) {
	if err = s.checkMenuPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		menu := &model.Menu{}
		if err = s.dao.LockObjectByIDWithoutPStoreId(ctx, menu, req.MenuId, req.Token.SgId); err != nil {
			return
		}
		if err = s.dao.CheckMenuProdsExists(ctx, req.MenuId, []uint64{req.ProdId}); err != nil {
			if errors.Cause(err) != gorm.ErrRecordNotFound {
				err = ecode.AppendMessage(constant.ErrNeedRefresh, "所选商品不在供货组，无法编辑")
				return
			}
			return
		}
		var (
			skus       []*model.MenuSkuQueryModel
			menuStores []*model.MenuStore
			nsqMsg     []byte
		)
		skuMap := make(map[uint64]*model.MenuSkuQueryModel)
		if skus, err = s.dao.GetMenuSkuInfoByProdIds(ctx, req.MenuId, []uint64{req.ProdId}); err != nil {
			return
		}
		for _, sku := range skus {
			skuMap[sku.SkuId] = sku
		}
		needNotify := false
		for _, sku := range req.Skus {
			if menuSku, ok := skuMap[sku.Id]; !ok {
				err = ecode.AppendMessage(constant.ErrNeedRefresh, "所选规格无法在商品信息中找到，请刷新列表再试")
			} else {
				if menuSku.MenuPrice.Valid && sku.Price == uint32(menuSku.MenuPrice.Int64) {
					delete(skuMap, sku.Id)
					continue
				}
				menuSkuModel := &model.MenuSku{
					MenuId:   req.MenuId,
					ProdId:   req.ProdId,
					SkuId:    sku.Id,
					Price:    sku.Price,
					SgId:     req.Token.SgId,
					Operator: req.Token.EmpId,
					Status:   true,
				}
				if err = s.dao.InsertOrUpdate(ctx, menuSkuModel); err != nil {
					return
				}
				needNotify = true
			}
		}
		if len(skuMap) != 0 {
			for skuId, sku := range skuMap {
				menuSkuModel := &model.MenuSku{
					MenuId:   req.MenuId,
					ProdId:   req.ProdId,
					SkuId:    skuId,
					Price:    sku.SkuPrice,
					SgId:     req.Token.SgId,
					Operator: req.Token.EmpId,
					Status:   false,
				}
				if err = s.dao.Save(ctx, menuSkuModel); err != nil {
					return
				}
				needNotify = true
			}
		}
		if needNotify {
			if menuStores, err = s.dao.GetMenuStores(ctx, req.MenuId); err != nil {
				return
			}
			if len(menuStores) != 0 {
				var storeMsgs []*prod.MenuUpdateMessage_StoreMessage
				for _, menuStore := range menuStores {
					storeMsgs = append(storeMsgs, &prod.MenuUpdateMessage_StoreMessage{
						StoreId:   menuStore.StoreId,
						DelIds:    make([]uint64, 0),
						UpdateIds: []uint64{req.ProdId},
					})
				}
				if nsqMsg, err = json.Marshal(&prod.MenuUpdateMessage{
					Stores:    storeMsgs,
					SgId:      req.Token.SgId,
					Timestamp: time.Now().Local().Unix(),
				}); err != nil {
					err = ecode.WithStack(err)
					return
				}
				if err = s.dao.PublishUniqueNSQMessage(
					ctx, constant.TopicMenuUpdate, nsqMsg); err != nil {
					return err
				}
			}
		}
		return
	}); err != nil {
		return
	}
	resp = &prod.DefaultResp{Status: true}
	return
}

// 批量将商品移除供货组
func (s *Service) BatchDeleteMenuProd(ctx context.Context, req *prod.BatchMenuProdsRequest) (resp *prod.DefaultResp, err error) {
	if err = s.checkMenuPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		menu := &model.Menu{}
		if err = s.dao.LockObjectByIDWithoutPStoreId(ctx, menu, req.MenuId, req.Token.SgId); err != nil {
			return
		}
		var (
			menuProds  []*model.MenuProd
			menuStores []*model.MenuStore
			nsqMsg     []byte
		)
		if menuProds, err = s.dao.GetMenuProdsByProdIds(ctx, req.MenuId, req.ProdIds); err != nil {
			return
		}
		if len(menuProds) != len(req.ProdIds) {
			err = ecode.AppendMessage(constant.ErrNeedRefresh, "所选商品不在当前供货组中，无法删除")
			return
		}
		if err = s.dao.DeleteMenuProdByIds(ctx, req.MenuId, req.ProdIds, req.Token.EmpId); err != nil {
			return
		}
		if menuStores, err = s.dao.GetMenuStores(ctx, req.MenuId); err != nil {
			return
		}
		if len(menuStores) != 0 {
			var storeMsgs []*prod.MenuUpdateMessage_StoreMessage
			for _, menuStore := range menuStores {
				storeMsgs = append(storeMsgs, &prod.MenuUpdateMessage_StoreMessage{
					StoreId:   menuStore.StoreId,
					DelIds:    req.ProdIds,
					UpdateIds: make([]uint64, 0),
				})
			}
			if nsqMsg, err = json.Marshal(&prod.MenuUpdateMessage{
				Stores:    storeMsgs,
				SgId:      req.Token.SgId,
				Timestamp: time.Now().Local().Unix(),
			}); err != nil {
				err = ecode.WithStack(err)
				return
			}
			if err = s.dao.PublishUniqueNSQMessage(
				ctx, constant.TopicMenuUpdate, nsqMsg); err != nil {
				return err
			}
		}
		return
	}); err != nil {
		return
	}
	resp = &prod.DefaultResp{Status: true}
	return
}
